<!DOCTYPE html>
<!-- Like custom-elements/form-associated/ElementInternals-setFormValue,
  but without any ordering assumptions about iframe loads and promise
  microtasks, to test the form submissions despite Servo's racey iframe.
  Includes web-platform-tests/wpt#21747 change to initial values. -->
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="container1"></div>
<div id="container2"></div>
<div id="container3"></div>
<div id="container4"></div>
<div id="container5"></div>
<div id="container6"></div>
<script>
class MyControl extends HTMLElement {
  static get formAssociated() { return true; }

  constructor() {
    super();
    this.internals_ = this.attachInternals();
    this.value_ = '';
  }

  get value() {
    return this.value_;
  }
  set value(v) {
    this.internals_.setFormValue(v);
    this.value_ = v;
  }
  setValues(nameValues) {
    const formData = new FormData();
    for (let p of nameValues) {
      formData.append(p[0], p[1]);
    }
    this.internals_.setFormValue(formData);
  }
}
customElements.define('my-control', MyControl);
const $ = document.querySelector.bind(document);

function submitPromise(t, n) {
  return new Promise((resolve, reject) => {
    const iframe = $('#container'+n+' iframe');
    iframe.onload = () => {
      if(iframe.contentWindow.location.href == "about:blank") { return; }
      resolve(iframe.contentWindow.location.search);
    }
    iframe.onerror = () => reject(new Error('iframe onerror fired'));
    $('#container'+n+' form').submit();
  });
}

promise_test(t => {
  $('#container1').innerHTML = '<form action="/common/blank.html" target="if1">' +
      '<input name=name-pd1 value="value-pd1">' +
      '<my-control></my-control>' +
      '</form>' +
      '<iframe name="if1"></iframe>';
  return submitPromise(t,1).then(query => {
    assert_equals(query, '?name-pd1=value-pd1');
  });
}, 'Single value - name is missing');

promise_test(t => {
  $('#container2').innerHTML = '<form action="/common/blank.html" target="if2">' +
      '<input name=name-pd1 value="value-pd1">' +
      '<my-control name=""></my-control>' +
      '<input name=name-pd2 value="value-pd2">' +
      '</form>' +
      '<iframe name="if2"></iframe>';
  $('#container2 my-control').value = 'value-ce1';
  return submitPromise(t,2).then(query => {
    assert_equals(query, '?name-pd1=value-pd1&name-pd2=value-pd2');
  });
}, 'Single value - empty name exists');

promise_test(t => {
  $('#container3').innerHTML = '<form action="/common/blank.html" target="if3" accept-charset=utf-8>' +
      '<input name=name-pd1 value="value-pd1">' +
      '<my-control name="name-ce1"></my-control>' +
      '<my-control name="name-usv"></my-control>' +
      '<my-control name="name-file"></my-control>' +
      '</form>' +
      '<iframe name="if3"></iframe>';
  const USV_INPUT = 'abc\uDC00\uD800def';
  const USV_OUTPUT = 'abc\uFFFD\uFFFDdef';
  const FILE_NAME = 'test_file.txt';
  $('#container3 [name=name-usv]').value = USV_INPUT;
  $('#container3 [name=name-file]').value = new File(['file content'], FILE_NAME);
  return submitPromise(t,3).then(query => {
    assert_equals(query, `?name-pd1=value-pd1&name-usv=${encodeURIComponent(USV_OUTPUT)}&name-file=${FILE_NAME}`);
  });
}, 'Single value - Non-empty name exists');

promise_test(t => {
  $('#container4').innerHTML = '<form action="/common/blank.html" target="if4">' +
      '<input name=name-pd1 value="value-pd1">' +
      '<my-control name="name-ce1"></my-control>' +
      '<my-control name="name-ce2"></my-control>' +
      '</form>' +
      '<iframe name="if4"></iframe>';
  $('#container4 my-control').value = null;
  return submitPromise(t,4).then(query => {
    assert_equals(query, '?name-pd1=value-pd1');
  });
}, 'Null value should submit nothing');

promise_test(t => {
  $('#container5').innerHTML = '<form action="/common/blank.html" target="if5">' +
      '<input name=name-pd1 value="value-pd1">' +
      '<my-control name=name-ce1></my-control>' +
      '</form>' +
      '<iframe name="if5"></iframe>';
  $('#container5 my-control').value = 'value-ce1';
  $('#container5 my-control').setValues([]);
  $('#container5 my-control').setValues([['sub1', 'subvalue1'],
                                         ['sub2', 'subvalue2'],
                                         ['sub2', 'subvalue3']]);
  return submitPromise(t,5).then(query => {
    assert_equals(query, '?name-pd1=value-pd1&sub1=subvalue1&sub2=subvalue2&sub2=subvalue3');
  });
}, 'Multiple values - name content attribute is ignored');

promise_test(t => {
  $('#container6').innerHTML = '<form action="/common/blank.html" target="if6">' +
      '<input name=name-pd1 value="value-pd1">' +
      '<my-control name=name-ce1></my-control>' +
      '</form>' +
      '<iframe name="if6"></iframe>';
  $('#container6 my-control').value = 'value-ce1';
  $('#container6 my-control').setValues([]);
  return submitPromise(t,6).then(query => {
    assert_equals(query, '?name-pd1=value-pd1');
  });
}, 'setFormValue with an empty FormData should submit nothing');
</script>
